#!/usr/bin/env python
# -*- coding: utf-8 -*-

__author__ = 'Michael Liao (askxuefeng@gmail.com)'

'''
build.py

- count lines of code

- pre-compile all views for speed

- make package (.zip) file for publish.
'''

import re
import os

from framework import view

PACKAGE_EXCLUDES = (
        r'^.*\.pyc$',                    # *.pyc
        r'^\/[a-zA-Z0-9\_]+\/view\/.*$', # /*/view/**
        r'^.*\_test$',                   # *_test
        r'^.*\_test\.py',                # *_test.py
        r'^\/build\.py$',                # /build.py
)

REGEX_EXCLUDES = []
for regex in PACKAGE_EXCLUDES:
    REGEX_EXCLUDES.append(re.compile(regex))

def main():
    '''
    Build ExpressMe by package() and deploy().
    '''
    root = os.path.split(__file__)[0]
    count_line(root)
    compile_view(root)
    package(root)

def count_line(root_path):
    print 'counting lines of code...'
    ignores = ('atom', 'boto', 'Cheetah', 'compiled', 'gdata', 'static', 'Templates', 'theme')
    all_dirs = os.listdir(root_path)
    valid_dirs = [d for d in all_dirs if d not in ignores and os.path.isdir(os.path.join(root_path, d))]
    total_code = 0
    total_test = 0
    c, t = _count_dir('', root_path)
    total_code += c
    total_test += t
    for d in valid_dirs:
        c, t = _count_dir(d, os.path.join(root_path, d))
        total_code += c
        total_test += t
    print 'total about %d lines: logic / test = %d / %d.' % ((total_code + total_test), total_code, total_test,)

def _count_dir(app, path):
    code_lines = 0
    test_lines = 0
    all_files = os.listdir(path)
    py_files = [f for f in all_files if f.endswith('.py')]
    for f in py_files:
        n = _count_file(os.path.join(path, f))
        if app.endswith('test') or f.endswith('test.py') or f.endswith('tests.py') or f.endswith('gaeunit.py'):
            test_lines += n
        elif not f[-1] in ',{(\\':
            code_lines += n
    if app:
        print '  dir "%s" contains about %d lines: logic / test = %d / %d.' % (app, code_lines + test_lines, code_lines, test_lines)
    return code_lines, test_lines

def _count_file(file_path):
    lines = 0
    f = open(file_path, 'r')
    for l in f:
        s = l.strip()
        if s and not s.startswith('#'):
            lines = lines + 1
    f.close()
    return lines

def package(root_path):
    '''
    Compile all views and make a zip file.
    '''
    fs = os.listdir(root_path)

def compile_view(root_path):
    all_appdirs = os.listdir(root_path)
    appdirs = [app for app in all_appdirs if not app.endswith('test') and os.path.isdir(os.path.join(root_path, app, 'view'))]
    appdirs.sort()
    count = 0
    for app in appdirs:
        if app=='theme':
            import theme
            themes = theme.get_themes(False)
            for t in themes:
                count += _compile_dir(root_path, app, view_dir=t)
        else:
            count += _compile_dir(root_path, app)
    # make sure __init__.py under root_path/compiled:
    _gen_init_py(os.path.join(root_path, 'compiled'))
    print 'total %d view(s) compiled.' % count

def _compile_dir(root_path, app, view_dir='view'):
    print 'compile views in "%s" for app "%s"...' % (view_dir, app)
    all_views = os.listdir(os.path.join(root_path, app, view_dir))
    views = [v for v in all_views if os.path.isfile(os.path.join(root_path, app, view_dir, v))]
    count = 0
    for v in views:
        if v.endswith('.html'):
            print '  compile "%s"...' % v
            mod_name = v[:-5]
            content = view.compile_template(app, mod_name, view_dir=view_dir)
            content_dir = os.path.join(root_path, 'compiled', app, view_dir)
            _mkdirs(content_dir)
            _gen_init_py(content_dir)
            file = os.path.join(content_dir, '%s.py' % mod_name)
            f = open(file, 'w')
            f.write(content)
            f.close()
            count += 1
    app_dir = os.path.join(root_path, 'compiled', app)
    _mkdirs(app_dir)
    _gen_init_py(app_dir)
    print '%d view(s) compiled.' % count
    return count

def _filter(path, root_path):
    relative = path[len(root_path):].replace(os.sep, '/')
    for m in REGEX_EXCLUDES:
        if m.match(relative) is not None:
            return False
    return True

def _mkdirs(path):
    if os.path.isdir(path):
        return
    os.makedirs(path)

def _gen_init_py(package_path):
    file = open(os.path.join(package_path, '__init__.py'), 'w')
    file.write(r'''#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# DO NOT modify this file because it was generated by 'build.py'
#
''')
    file.close()

if __name__ == '__main__':
    main()
